<?php

class AFClassException extends AFException {};

class AFClass
{
	public function getClassName()
	{
		return get_class($this);
	}

//	public function __construct()
//	{
//	}

	public function __call($key, $args)
	{
		$backtrace = debug_backtrace();
		$last = $backtrace[count($backtrace)-1];
		throw new AFClassException('Call of undeclared method '.$last['class'].$last['type'].$key.'('.count($args).' args)', 1);
	}

	public function __get($key)
	{
		throw new AFClassException('Request of undefined property '.$key, 0);
	}

	public function __invoke()
	{
		$backtrace = debug_backtrace();
		$last = $backtrace[count($backtrace)-1];
		throw new AFClassException('Don`t know how to invoke class '.$this->getClassName(), 0);
	}

	public function dump()
	{
		$ref = new ReflectionObject($this);
//		$static = $ref->getProperties(ReflectionProperty::IS_STATIC);

		$properties = array(
			'public' => $ref->getProperties(ReflectionProperty::IS_PUBLIC),
			'private' => $ref->getProperties(ReflectionProperty::IS_PRIVATE),
			'protected' => $ref->getProperties(ReflectionProperty::IS_PROTECTED)
		);

		$methods = array(
			'public' => $ref->getMethods(ReflectionProperty::IS_PUBLIC),
			'private' => $ref->getMethods(ReflectionProperty::IS_PRIVATE),
			'protected' => $ref->getMethods(ReflectionProperty::IS_PROTECTED)
		);

/*		$properties = $ref->getProperties();
		foreach($properties as $property)
		{
//			echo '<div>'.highlight_string(join(' ', Reflection::getModifierNames($property->getModifiers())).' $'.$property->name, TRUE).'</div>';
			echo '<div>'.FN::highlightLine(join(' ', Reflection::getModifierNames($property->getModifiers())).' $'.$property->name).'</div>';
		}
		$methods = $ref->getMethods();
		foreach($methods as $method)
		{
			echo '<div>'.FN::highlightLine(join(' ', Reflection::getModifierNames($method->getModifiers())).' '.$method->name.'()').'</div>';
		}*/
		AFDebugger::debugStart('<b>'.$this->getClassName().'</b> instance dump');
		echo "<pre>";
		echo "<i>Hierarchy</i>\n";
		echo '    <b>' . get_class($this) . '</b> extends ' . join(' extends ', array_map(function($className){return '<b>'.$className.'</b>';}, class_parents($this))) . "\n";
		echo "<i>Properties</i>\n";
		foreach($properties as $bunchName => $bunch)
		{
			if(count($bunch))
			{
				echo '    <b>'.$bunchName.':</b>'."\n";
				foreach($bunch as $property)
				{
					if($property->isStatic())
					{
						continue;
					}
					$name = $property->name;
					echo "      ".FN::highlightLine(join(' ', Reflection::getModifierNames($property->getModifiers())).' $'.$property->name.' = '.(($bunchName == 'private')?'???':var_export($this->$name, TRUE)))."\n";
				}
			}
		}
		echo "<i>Methods</i>\n";
		foreach($methods as $name => $bunch)
		{
			if(count($bunch))
			{
				echo '    <b>'.$name.':</b>'."\n";
				foreach($bunch as $method)
				{
					if($method->isStatic())
					{
						continue;
					}
					$params = $method->getParameters();
					$params = array_map(function($el){
						return '$'.$el->getName().($el->isDefaultValueAvailable()?' = '.$el->getDefaultValue():'');
					}, $params);
					echo "      ".FN::highlightLine(join(' ', Reflection::getModifierNames($method->getModifiers())).' '.$method->name).'('.join(', ', $params).')'."\n";
				}
			}
		}
		echo "</pre>";
		AFDebugger::debugEnd();
	}
}

//abstract class Object extends AFClass {};

//abstract class AFObject extends AFClass {};

?>
